package org.javaboy.my_login_page.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;

@Configuration
public class SecurityConfig {

    /**
     * 一般前端静态页面，可以使用这种方案放行
     * @return
     */
    @Bean
    WebSecurityCustomizer webSecurityCustomizer() {
        // /hello2 不用登录就可以访问
        return web -> web.ignoring().requestMatchers("/hello2");
    }

    @Bean
    UserDetailsService us() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("zhangsan").password("{noop}123").roles("admin").build());
        return manager;
    }

    /**
     * http 中保存的就是默认的过滤器的配置
     *
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                //所有请求都需要认证之后才能访问
                .authorizeHttpRequests(a ->
                        a
//                                .requestMatchers("/hello2")
                                //接口的匿名访问，一般建议使用这种方案
                                //登录或者不登录都能访问
//                                .permitAll()
                                //这个表示只允许匿名访问
//                                .anonymous()
                                .anyRequest().authenticated())
                //配置表单登录
                .formLogin(f -> f
                        //默认 username
                        .usernameParameter("uname")
                        //默认是 password
                        .passwordParameter("password")
                        //登录页面，不配置，默认就是 /login（GET）
                        .loginPage("/login.html")
                        //登录接口，不配置，默认就是 /login（POST）
                        .loginProcessingUrl("/login")
                        //登录成功之后的跳转页面，这个是服务端跳转，不推荐
                        //ForwardAuthenticationSuccessHandler
//                        .successForwardUrl("/hello")
                        //客户端跳转，第二个参数表示是否总是使用这个跳转地址
                        //默认情况下，如果访问存在缓存的请求，则登录成功之后，跳转到缓存的地址，否则才会跳转到这里指定的地址
                        //如果第二个参数为 true，则不考虑缓存的请求，登录成功之后，都跳转到这里指定的地址
//                        .defaultSuccessUrl("/hello",true)
                        //自定义登录成功的处理器
//                        .successHandler((request, response, authentication) -> {
//                            //获取当前登录成功的用户对象
//                            Object principal = authentication.getPrincipal();
//                            ObjectMapper om = new ObjectMapper();
//                            String s = om.writeValueAsString(principal);
//                            response.setContentType("application/json;charset=utf-8");
//                            response.getWriter().write(s);
//                        })
                        .successHandler(successHandler())
                        //登录失败后服务端跳转
//                        .failureForwardUrl()
                        //登录失败后客户端跳转
//                        .failureUrl()
                        .failureHandler((request, response, exception) -> {
                            response.getWriter().write("error");
                        })
                        .permitAll())
                .logout(l -> l
                        .logoutRequestMatcher(new OrRequestMatcher(
                                new AntPathRequestMatcher("/logout1", "GET"),
                                new AntPathRequestMatcher("/logout2", "POST")))
                        //注销登录的地址
//                        .logoutUrl("/logout")
                        .defaultLogoutSuccessHandlerFor((request, response, authentication) -> {
                            response.getWriter().write("logout1-logout");
                        }, new AntPathRequestMatcher("/logout1", "GET"))
                        .defaultLogoutSuccessHandlerFor((request, response, authentication) -> {
                            response.getWriter().write("logout2-logout");
                        }, new AntPathRequestMatcher("/logout2", "POST"))
                        //销毁 httpsession，默认就是 true
                        .invalidateHttpSession(true)
                        //清除 Cookie
                        .deleteCookies()
                        //清除认证信息
                        .clearAuthentication(true)
                        //注销成功后跳转的地址
//                        .logoutSuccessUrl("/login.html")
                        .permitAll())
                //关闭 CSRF 校验，本质上就是从过滤器链中移除 CsrfFilter
                .csrf(c -> c.disable());
        return http.build();
    }

    SavedRequestAwareAuthenticationSuccessHandler successHandler() {
        SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler();
        handler.setTargetUrlParameter("target");
        return handler;
    }

    /**
     * 配置 Spring Security 过滤器链
     * @return
     */
/*    @Bean
    SecurityFilterChain securityFilterChain() {
        //这个配置就表示拦截所有请求，并且不经过任何过滤器
        return new DefaultSecurityFilterChain(new AntPathRequestMatcher("/**"));
    }*/
}
